/*
 * TraceCmdList.c
 *    Define processes about LINKCOMMANDLIST  here
 *	   1. define the TRACE-FLOW of commands that are in a PATH.
 *  Created on: 2012/07/04
 *      Author: guanxiaoying
 */
#include "../tracedef.h"
#include "trace_cmd.h"


/*
 * get the next COMMAND-LIST of "astCmdList" which is in the current PATH.
 */
static AST traceCmdGetNext( AST astCmdList ){
	/* kind of COMMAND-LIST */
	U4 kind = stCmdListAccess.opKind.get( astCmdList );
	/* condition:PATH_TRUE or PATH_FALSE */
	U2 pathFlg = Tr_PathGetCurrConditionInTracing();
	AST astResult=0;
	AST astOperand;
	switch(kind){
	case ASM_CMD_CHOOSE :
	case ASM_CMD_BRANCH  :
		/* has two next PATHs */
		if( pathFlg == PATH_FALSE ){
			/* get the second one if PATH_FALSE */
			astOperand = stCmdListAccess.rightOperand.get( astCmdList );
		}else{
			/* get the first one if PATH_TRUE */
			astOperand = stCmdListAccess.leftOperand.get( astCmdList );
		}
		/* for BRANCH and CHOOSE, the operands are always COMMAND-LIST,
		 * so no check.
		 */
		astResult = stOperandAccess.parameter.get( astOperand );
		break;
	case ASM_CMD_JUMP  :
		/* get the jump destination  */
		astOperand = stCmdListAccess.leftOperand.get( astCmdList );
		astResult = stOperandAccess.parameter.get( astOperand );
		break;
	case ASM_CMD_FUNCEXIT:
		/* it's the end of a function, should not has any next COMMAND */
		astResult = 0;
		break;
	default:
		/* no branch, just get next  */
		astResult = stCmdListAccess.next.get( astCmdList );
		break;
	}
	return astResult;
}
/* trace the ASM_CMD_RETURN command */
/* no effect for TRACE-FLOW, so do nothing here */
static S4 traceReturnCmdList( VOID ){
	S4 rc = TRACEEXIT_SUCCESS;
	/* only call the information recorder */
	rc = Tr_RecInfo( stCmdCurrTraceInfo.astTable, EVENT_CMDLIST_PREV );

	return rc;
}
/* trace the ASM_CMD_GETOPERAND command */
/* no effect for TRACE-FLOW, so do nothing here */
static S4 tracePrimaryCmdList( VOID ){
	S4 rc = TRACEEXIT_SUCCESS;

	/* only call the information recorder */
	rc = Tr_RecInfo( stCmdCurrTraceInfo.astTable, EVENT_CMDLIST_PREV );
	return rc;
}
/* trace the ASM_CMD_GETOFFSET_UNIT, ASM_CMD_GETOFFSET commands */
/* no effect for TRACE-FLOW, so do nothing here */
static S4 tracePostfixCmdList( VOID ){
	S4 rc = TRACEEXIT_SUCCESS;

	rc = Tr_RecInfo( stCmdCurrTraceInfo.astTable, EVENT_CMDLIST_PREV );
	return rc;
}
/* trace the commands as below */
/* 	 ASM_CMD_GETMEMDATA
	 ASM_CMD_GETADDR
	 ASM_CMD_MINUS
	 ASM_CMD_NEGATION
	 ASM_CMD_BITNEGATION
*/
/* no effect for TRACE-FLOW, so do nothing here */
static S4 traceUnaryCmdList( VOID ){
	S4 rc = TRACEEXIT_SUCCESS;
	/* only call the information recorder */
	rc = Tr_RecInfo( stCmdCurrTraceInfo.astTable, EVENT_CMDLIST_PREV );
	return rc;
}
/* trace the commands ASM_CMD_INC */
/* no effect for TRACE-FLOW, so do nothing here */
static S4 traceIncCmdList( VOID ){
	S4 rc = TRACEEXIT_SUCCESS;
	/* only call the information recorder */
	rc = Tr_RecInfo( stCmdCurrTraceInfo.astTable, EVENT_CMDLIST_PREV );
	return rc;
}
/* trace the commands ASM_CMD_DEC */
/* no effect for TRACE-FLOW, so do nothing here */
static S4 traceDecCmdList( VOID ){
	S4 rc = TRACEEXIT_SUCCESS;
	/* only call the information recorder */
	rc = Tr_RecInfo( stCmdCurrTraceInfo.astTable, EVENT_CMDLIST_PREV );
	return rc;
}
/* trace the commands ASM_CMD_CAST */
/* no effect for TRACE-FLOW, so do nothing here */
static S4 traceCastCmdList( VOID ){
	S4 rc = TRACEEXIT_SUCCESS;

	rc = Tr_RecInfo( stCmdCurrTraceInfo.astTable, EVENT_CMDLIST_PREV );
	return rc;
}
/* trace the commands as below */
/*
 * 	 ASM_CMD_MUL
	 ASM_CMD_DIV
	 ASM_CMD_MOD
	 ASM_CMD_ADD
	 ASM_CMD_SUB
 */
/* no effect for TRACE-FLOW, so do nothing here */
static S4 traceArithCmdList( VOID ){
	S4 rc = TRACEEXIT_SUCCESS;
	/* only call the information recorder */
	rc = Tr_RecInfo( stCmdCurrTraceInfo.astTable, EVENT_CMDLIST_PREV );
	return rc;
}
/* trace the commands as below */
/*
 * 	 ASM_CMD_LSFT
	 ASM_CMD_RSFT
 */
/* no effect for TRACE-FLOW, so do nothing here */
static S4 traceSftCmdList( VOID ){
	S4 rc = TRACEEXIT_SUCCESS;
	/* only call the information recorder */
	rc = Tr_RecInfo( stCmdCurrTraceInfo.astTable, EVENT_CMDLIST_PREV );
	return rc;
}
/* trace the commands as below */
/*
	 ASM_CMD_GREATER
	 ASM_CMD_GREATEREQUAL
	 ASM_CMD_LESS
	 ASM_CMD_LESSEQUAL
 */
/* no effect for TRACE-FLOW, so do nothing here */
static S4 traceRelationCmdList( VOID ){
	S4 rc = TRACEEXIT_SUCCESS;
	/* only call the information recorder */
	rc = Tr_RecInfo( stCmdCurrTraceInfo.astTable, EVENT_CMDLIST_PREV );
	return rc;
}
/* trace the commands as below */
/*
	 ASM_CMD_EQUAL
	 ASM_CMD_UNEQUAL
 */
/* no effect for TRACE-FLOW, so do nothing here */
static S4 traceEqualCmdList( VOID ){
	S4 rc = TRACEEXIT_SUCCESS;

	rc = Tr_RecInfo( stCmdCurrTraceInfo.astTable, EVENT_CMDLIST_PREV );
	return rc;
}
/* trace the commands as below */
/*
	 ASM_CMD_BITAND
	 ASM_CMD_BITEXOR
	 ASM_CMD_BITINOR
 */
/* no effect for TRACE-FLOW, so do nothing here */
static S4 traceBitCmdList( VOID ){
	S4 rc = TRACEEXIT_SUCCESS;
	/* only call the information recorder */
	rc = Tr_RecInfo( stCmdCurrTraceInfo.astTable, EVENT_CMDLIST_PREV );
	return rc;
}
/* trace the commands as below */
/*
	 ASM_CMD_LGAND
	 ASM_CMD_LGOR
 */
/* no effect for TRACE-FLOW, so do nothing here */
static S4 traceLogicCmdList( VOID ){
	S4 rc = TRACEEXIT_SUCCESS;
	/* only call the information recorder */
	rc = Tr_RecInfo( stCmdCurrTraceInfo.astTable, EVENT_CMDLIST_PREV );
	return rc;
}
/* trace the commands as below */
/*
	 ASM_CMD_ASSIGN
 */
/* no effect for TRACE-FLOW, so do nothing here */
static S4 traceAssignCmdList( VOID ){
	S4 rc = TRACEEXIT_SUCCESS;
	/* only call the information recorder */
	rc = Tr_RecInfo( stCmdCurrTraceInfo.astTable, EVENT_CMDLIST_PREV );
	return rc;
}
/* trace the commands as below */
/*
	 ASM_CMD_ASSIGNARG
 */
/* no effect for TRACE-FLOW, so do nothing here */
static S4 traceAssignArgCmdList( VOID ){
	S4 rc = TRACEEXIT_SUCCESS;
	/* only call the information recorder */
	rc = Tr_RecInfo(stCmdCurrTraceInfo.astTable,  EVENT_CMDLIST_PREV );
	return rc;
}
static S4 traceOthersCmdList( VOID ){
	S4 rc = TRACEEXIT_SUCCESS;

	rc = Tr_RecInfo( stCmdCurrTraceInfo.astTable, EVENT_CMDLIST_PREV );
	return rc;
}
/* for ASM_CMD_CALL */
static S4 traceFuncCallCmdList( VOID ){
	S4 rc = TRACEEXIT_SUCCESS;
	AST astFunction;

	rc = Tr_RecInfo( stCmdCurrTraceInfo.astTable, EVENT_CMDLIST_PREV );
	if( rc == TRACEEXIT_FATAL ){
		return rc;
	}

	if( stCmdTraceOption.ucCallFuncBody ){
		/* try to go into the callee function */
		astFunction = stCmdTraceOption.pGetCallee( stCmdCurrTraceInfo.astTable );
		if( astFunction > 0 ){
			rc = Tr_FunctionEntry( astFunction );
			if( rc != TRACEEXIT_SUCCESS ){
				/* TRACEEXIT_END will be returned if succeeded */
				return rc;
			}
		}
	}
	return TRACEEXIT_SUCCESS;
}
static S4  traceCmdControl( VOID ){
	U4 kind = stCmdListAccess.opKind.get( stCmdCurrTraceInfo.astTable );
	S4 rc = TRACEEXIT_SUCCESS;
	TRY;
	switch(kind){
	case ASM_CMD_RETURN  :
		rc = traceReturnCmdList();
		break;
	case ASM_CMD_GETOPERAND  :
		rc = tracePrimaryCmdList();
		break;
	case ASM_CMD_GETOFFSET_UNIT   :
	case ASM_CMD_GETOFFSET    :
		rc = tracePostfixCmdList();
		break;
	case ASM_CMD_GETMEMDATA   :
	case ASM_CMD_GETADDR  :
	case ASM_CMD_MINUS  :
	case ASM_CMD_NEGATION :
	case ASM_CMD_BITNEGATION :
		rc = traceUnaryCmdList();
		break;
	case ASM_CMD_CALL  :
		rc = traceFuncCallCmdList();
		break;
	case ASM_CMD_INC  :
		rc = traceIncCmdList();
		break;
	case ASM_CMD_DEC  :
		rc = traceDecCmdList();
		break;
	case ASM_CMD_CAST   :
		rc = traceCastCmdList();
		break;
	case ASM_CMD_MUL   :
	case ASM_CMD_DIV   :
	case ASM_CMD_MOD   :
	case ASM_CMD_ADD  :
	case ASM_CMD_SUB  :
		rc = traceArithCmdList();
		break;
	case ASM_CMD_LSFT   :
	case ASM_CMD_RSFT   :
		rc = traceSftCmdList();
		break;
	case ASM_CMD_GREATER   :
	case ASM_CMD_GREATEREQUAL   :
	case ASM_CMD_LESS   :
	case ASM_CMD_LESSEQUAL   :
		rc = traceRelationCmdList();
		break;
	case ASM_CMD_EQUAL   :
	case ASM_CMD_UNEQUAL   :
		rc = traceEqualCmdList();
		break;
	case ASM_CMD_BITAND   :
	case ASM_CMD_BITEXOR   :
	case ASM_CMD_BITINOR  :
		rc = traceBitCmdList();
		break;
	case ASM_CMD_LGAND   :
	case ASM_CMD_LGOR   :
		rc = traceLogicCmdList();
		break;
	case ASM_CMD_ASSIGN   :
		rc = traceAssignCmdList();
		break;
	case ASM_CMD_ASSIGNARG   :
		rc = traceAssignArgCmdList();
		break;
	default:
		//	case ASM_CMD_NOP   :
		//	case ASM_CMD_CHOOSE :
		//	case ASM_CMD_CHOOSEEND :
		//	case ASM_CMD_CONFLUX  :
		//	case ASM_CMD_JUMP  :
		//	case ASM_CMD_JUDGE  :
		//	case ASM_CMD_BRANCH  :
		//	case ASM_CMD_FUNCENTRY  :
		//	case ASM_CMD_FUNCEXIT   :
		rc = traceOthersCmdList();
		break;
	}
	CATCH(TRACEEXIT_FATAL);
	return rc;
}

S4 Tr_CmdAtOnePath( VOID ){
	S4 rc = TRACEEXIT_SUCCESS;
	AST  astBeginList;
	AST  astEndList;

	astBeginList = stCmdPathInfoAccess.beginNode.get( stCmdCurrTraceInfo.astPath );
	astEndList = stCmdPathInfoAccess.endNode.get( stCmdCurrTraceInfo.astPath );

	/* "stCmdCurrTraceInfo.astTable" will be not zero only when it came back from a function,
	 * and continue tracing the path.
	 */
	if( stCmdCurrTraceInfo.astTable == 0 ){
		stCmdCurrTraceInfo.astTable = astBeginList;
		stCmdCurrTraceInfo.astNext = traceCmdGetNext(stCmdCurrTraceInfo.astTable);
	}
	while( 1 ){
		//Tr_PrintfCmdList(stCmdCurrTraceInfo.astTable);
		rc = traceCmdControl();
		if( rc != TRACEEXIT_SUCCESS ){
			/* break when it's about to go into callee function */
			break;
		}
		if( stCmdCurrTraceInfo.astTable == 0 || stCmdCurrTraceInfo.astTable == astEndList ){
			/* break when this PATH is over */
			break;
		}
		/* get NEXT */
		stCmdCurrTraceInfo.astTable = stCmdCurrTraceInfo.astNext;
		stCmdCurrTraceInfo.astNext = traceCmdGetNext(stCmdCurrTraceInfo.astTable);
	}
	stCmdCurrTraceInfo.astTable = 0;
	stCmdCurrTraceInfo.astNext = 0;
	return ( rc );
}
AST TraceCmdGetNextByPath( AST astCmdList, AST astPath ){
	/* kind of COMMAND-LIST */
	U4 kind = stCmdListAccess.opKind.get( astCmdList );
	/* condition:PATH_TRUE or PATH_FALSE */
	U2 pathFlg = stCmdPathInfoAccess.condition.get(astPath);
	AST astResult=0;
	AST astOperand;
	switch(kind){
	case ASM_CMD_CHOOSE :
	case ASM_CMD_BRANCH  :
		/* has two next PATHs */
		if( pathFlg == PATH_FALSE ){
			/* get the second one if PATH_FALSE */
			astOperand = stCmdListAccess.rightOperand.get( astCmdList );
		}else{
			/* get the first one if PATH_TRUE */
			astOperand = stCmdListAccess.leftOperand.get( astCmdList );
		}
		/* for BRANCH and CHOOSE, the operands are always COMMAND-LIST,
		 * so no check.
		 */
		astResult = stOperandAccess.parameter.get( astOperand );
		break;
	case ASM_CMD_JUMP  :
		/* get the jump destination  */
		astOperand = stCmdListAccess.leftOperand.get( astCmdList );
		astResult = stOperandAccess.parameter.get( astOperand );
		break;
	case ASM_CMD_FUNCEXIT:
		/* it's the end of a function, should not has any next COMMAND */
		astResult = 0;
		break;
	default:
		/* no branch, just get next  */
		astResult = stCmdListAccess.next.get( astCmdList );
		break;
	}
	return astResult;
}
